using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace GoodStuff.Web.Controls
{
    /// <summary>
    /// UI-Less asp-net control that extends all validators with the ability to update the style
    /// of the control and the associated label
    /// To associate the label with the validator, add the 'validatorLabel='[clientid]' to the validator.
    /// </summary>
    public class ValidatorExtension : Control
    {
        protected override void OnPreRender(EventArgs e)
        {
            //alleen wanneer er 'enabled' validators zijn.
            bool foundValidator = false;
            foreach (IValidator validator in Page.Validators)
            {
                BaseValidator baseValidator = validator as BaseValidator;
                if (baseValidator != null && baseValidator.Visible && baseValidator.EnableClientScript)
                {
                    foundValidator = true;
                    break;
                }
            }

            if (foundValidator == false)
            {
                return;
            }

            ScriptManager.RegisterStartupScript(this, typeof(ValidatorExtension), "extValidateStartup", @"
var __funcbody, newfunc;

__funcbody = ValidatorUpdateDisplay.toString();
__funcbody = __funcbody.substring(__funcbody.indexOf('{') + 1, 
                                 __funcbody.lastIndexOf('}'));

newfunc = new Function('val', 'extValidateOnChange(val); ' + 
                                             __funcbody );

ValidatorUpdateDisplay = newfunc;

", true);


            ScriptManager.RegisterClientScriptBlock(this, typeof(ValidatorExtension), "extValidateOnChange", @"
function extValidateOnChange(val)
{   
    //use getAttribute to enable case-insensivity in Firefox
    var labelClientID = val.getAttribute('labelClientID');
    if(labelClientID != null || labelClientID != undefined) {
        // Find label through naming rule
        var lbl = document.getElementById(labelClientID);
        var ctl = document.getElementById(val.getAttribute('controlToHiliteID'));
        var k, value;

        // Find out all validators associated
        var vals = new Array();
        for(k=0; k < Page_Validators.length; k++){
            if(Page_Validators[k].controltovalidate == val.controltovalidate){
                vals.push(Page_Validators[k]);
            }
        }

        //Determine if some validator fails
        value = true;
        for(k=0; k < vals.length;k++){
            value = (value && vals[k].isvalid);
        }

        // Change label text color
        if(value){
            lbl.className ='label'; // normal color, black
            ctl.style.borderColor = '';
            ctl.style.borderStyle = '';
        }else{
            lbl.className = 'errorLabel'; // error color, red
            ctl.style.borderColor = 'red';
            ctl.style.borderStyle = 'solid';
        }
    }
}
", true);

            foreach (IValidator validator in Page.Validators)
            {
                BaseValidator baseValidator = validator as BaseValidator;
                if (baseValidator != null && baseValidator.Visible)
                {
                    string controlToHilite = baseValidator.Attributes["controlToHilite"];
                    if (string.IsNullOrEmpty(controlToHilite))
                    {
                        controlToHilite = baseValidator.ControlToValidate;
                    }

                    Control controlToHiLiteControl = FindControlRecursive<Control>(baseValidator.Parent, controlToHilite);
                    if (controlToHiLiteControl == null)
                    {
                        throw new Exception("validator " + baseValidator.ID + " specified a controlToHilite '" + controlToHilite + "' that could not be found.");
                    }

                    baseValidator.Attributes.Add("controlToHiliteID", controlToHiLiteControl.ClientID);

                    string label = baseValidator.Attributes["validatorLabel"];
                    if (label != null)
                    {
                        //map the control id to clientid

                        //the label is property a sibling of the validator, so find it there.
                        Control labelControl = FindControlRecursive<Control>(baseValidator.Parent, label); //FindControlRecursive<Control>(baseValidator.Parent, label);
                        if (labelControl == null)
                        {
                            throw new Exception(string.Format("The label {0} for Validator {1} could not be found", label, baseValidator.ID));
                        }


                        baseValidator.Attributes["labelClientID"] = labelControl.ClientID;

                        if (this.Page.IsPostBack && baseValidator.Enabled)
                        {
                            //als de validator is langsgekomen serverside, kunnen we de labels alvast hiliten.
                            WebControl control = labelControl as WebControl;
                            if (control != null)
                            {
                                if (!baseValidator.IsValid)
                                {
                                    control.CssClass = "errorLabel";
                                }
                            }
                            else
                            {
                                throw new Exception("validator " + baseValidator.ID + " specified a labelControl that could not be found.");
                            }

                            Control inputControl = FindControlRecursive<Control>(baseValidator.Parent, controlToHilite);
                            if (inputControl != null)
                            {
                                if (inputControl is WebControl)
                                {
                                    WebControl inputWebControl = (WebControl)inputControl;
                                    if (!baseValidator.IsValid)
                                    {
                                        inputWebControl.BorderColor = System.Drawing.Color.Red;
                                        inputWebControl.BorderStyle = BorderStyle.Solid;
                                    }
                                }
                            }
                            else
                            {
                                throw new Exception("validator " + baseValidator.ID + " specified a controlToHilite '" + controlToHilite + "' that could not be found.");
                            }
                        }
                    }
                }
            }

            base.OnPreRender(e);
        }

        public static T FindControlRecursive<T>(Control startingControl, string id) where T : Control
        {
            foreach (Control activeControl in startingControl.Controls)
            {
                if (string.Compare(id, activeControl.ID, true) == 0)
                {
                    if (activeControl is T)
                    {
                        return (T)activeControl;
                    }
                    else
                    {
                        throw new Exception("The control with ID " + id + " was not of type " + typeof(T).Name);
                    }
                }
                else
                {
                    T found = FindControlRecursive<T>(activeControl, id);
                    if (found != null)
                    {
                        return found;
                    }
                }
            }
            return null;
        }
    }
}
